package com.ysd.lis.service.callNum.impl;

import cn.hutool.core.date.DateUtil;
import cn.hutool.json.JSONUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.CollectionUtils;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.github.yulichang.wrapper.MPJLambdaWrapper;
import com.ysd.common.Result;
import com.ysd.lis.entity.callNum.CallBusiness;
import com.ysd.lis.entity.callNum.CallWindow;
import com.ysd.lis.mapper.callNum.CallBusinessMapper;
import com.ysd.lis.mapper.callNum.CallWindowMapper;
import com.ysd.lis.request.callNum.CallBusinessVo;
import com.ysd.lis.service.callNum.CallBusinessService;
import com.ysd.lis.service.callNum.CallWindowService;
import com.ysd.lis.socket.MessageTemplate;
import com.ysd.lis.socket.WebSocketUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import javax.persistence.Transient;
import javax.transaction.Transactional;
import java.sql.Timestamp;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.stream.Collectors;

/**
 * <p>
 * 服务实现类
 * </p>
 *
 * @author wh
 * @since 2025-05-28
 */
@Service
public class CallBusinessServiceImpl extends ServiceImpl<CallBusinessMapper, CallBusiness> implements CallBusinessService {

    @Autowired
    private CallBusinessMapper callBusinessMapper;

    @Autowired
    private CallWindowMapper callWindowMapper;

    @Autowired
    private CallWindowService callWindowService;


    @Override
    public Result callNum(String userName) {
        Timestamp beginTime = DateUtil.beginOfDay(DateUtil.date()).toTimestamp();
        List<CallBusiness> callBusinesses = this.list(new LambdaQueryWrapper<CallBusiness>().eq(CallBusiness::getDelFlag, 0).ge(CallBusiness::getReqTime, beginTime));
        Map<String, List<CallBusiness>> bussinessByWinCode = callBusinesses.stream().collect(Collectors.groupingBy(CallBusiness::getWinCode));

        MPJLambdaWrapper<CallWindow> callWindowWrapper = new MPJLambdaWrapper<>();
        callWindowWrapper.distinct();
        callWindowWrapper.selectAll(CallWindow.class);
        callWindowWrapper.selectCollection(CallBusiness.class, CallWindow::getCallBusinesses);
        callWindowWrapper.leftJoin(CallBusiness.class, "cb", p -> p.eq(CallBusiness::getDelFlag, 0).eq(CallBusiness::getState, "5").eq(CallBusiness::getWinCode, CallWindow::getWinCode).ge(CallBusiness::getReqTime, beginTime));
        callWindowWrapper.eq(CallWindow::getIsEnable, 1);
        callWindowWrapper.eq(CallWindow::getDelFlag, 0);
        List<CallWindow> callWindowsList = callWindowMapper.selectJoinList(CallWindow.class, callWindowWrapper);
        for (CallWindow callWindow : callWindowsList) {
            int size = CollectionUtils.isEmpty(callWindow.getCallBusinesses()) ? 0 : callWindow.getCallBusinesses().size();
            callWindow.setBusinessesCount(size);
        }
        // callWindowsList集合根据businessesCount进行正序排序
        callWindowsList.sort((o1, o2) -> o1.getBusinessesCount() - o2.getBusinessesCount());
        CallWindow callWindow = callWindowsList.get(0);
        CallBusiness callBusiness = new CallBusiness();
        callBusiness.setReqTime(new Timestamp(System.currentTimeMillis()));
        // 根据窗口获取业务数据
        List<CallBusiness> callBusinesses1 = bussinessByWinCode.get(callWindow.getWinCode());
        int count = 1;
        if (CollectionUtils.isNotEmpty(callBusinesses1)) {
            count = callBusinesses1.size() + 1;
        }
        callBusiness.setBusinessNo(callWindow.getWinCode() + count);
        callBusiness.setWinCode(callWindow.getWinCode());
        callBusiness.setWinName(callWindow.getWinName());
        callBusiness.setUserName(userName);
        callBusiness.setSampleTypeCode(callWindow.getSampleTypeCode());
        callBusiness.setState("5");
        callBusinessMapper.insert(callBusiness);
        CallBusinessVo callBusinessVo = new CallBusinessVo();
        callBusinessVo.setWinName(callWindow.getWinName());
        callBusinessVo.setUserName(userName);
        callBusinessVo.setCallNum(callBusiness.getBusinessNo());
        callBusinessVo.setLinePeople(callWindow.getBusinessesCount());
        // 平均处理时间
        double avgTime = getAvgTime(callWindow.getWinCode());
        callBusinessVo.setExpectTime(avgTime);
        callBusinessVo.setNowTime(new Timestamp(System.currentTimeMillis()));

        MessageTemplate messageTemplate = new MessageTemplate();
        messageTemplate.setMessage(JSONUtil.toJsonStr(callBusiness));
        messageTemplate.setType("getNum");
        WebSocketUtils.sendAllMessage(messageTemplate);

        MessageTemplate nurseTemplate = new MessageTemplate();
        nurseTemplate.setMessage(JSONUtil.toJsonStr(callBusiness));
        nurseTemplate.setType("nurseGetCallNum");
        WebSocketUtils.sendAllMessage(nurseTemplate);
        return Result.succ(1, "", callBusinessVo);

    }

    @Override
    public Result netNum(String businessNo) {
        CallBusiness callBusiness = this.getOne(new LambdaQueryWrapper<CallBusiness>().eq(CallBusiness::getBusinessNo, businessNo).eq(CallBusiness::getDelFlag, 0));
        callBusiness.setState("10");
        Timestamp reqTime = callBusiness.getReqTime();
        Timestamp nowTime = new Timestamp(System.currentTimeMillis());
        // nowTime-reqTime 算出分钟
        callBusiness.setAvgTime((int) (nowTime.getTime() - reqTime.getTime()) / 60000);
        boolean b = this.updateById(callBusiness);
        if (b) {
            return Result.succ(1, "检验成功！", null);
        } else {
            return Result.fail("检验失败！");
        }
    }

    @Override
    @Transactional
    public Result closeWindow(String winCode) {
        Timestamp beginTime = DateUtil.beginOfDay(DateUtil.date()).toTimestamp();

        CallWindow callWindow1 = callWindowService.getOne(new LambdaQueryWrapper<CallWindow>().eq(CallWindow::getWinCode, winCode).eq(CallWindow::getDelFlag, 0));
        callWindow1.setIsEnable(0);
        callWindowService.updateById(callWindow1);
        LambdaQueryWrapper<CallBusiness> winWrapper = new LambdaQueryWrapper<>();
        winWrapper.eq(CallBusiness::getWinCode, winCode);
        winWrapper.eq(CallBusiness::getState, "5");
        winWrapper.eq(CallBusiness::getDelFlag, 0);
        List<CallBusiness> noBussinessList = this.list(winWrapper);

        MPJLambdaWrapper<CallWindow> callWindowWrapper = new MPJLambdaWrapper<>();
        callWindowWrapper.distinct();
        callWindowWrapper.selectAll(CallWindow.class);
        callWindowWrapper.selectCollection(CallBusiness.class, CallWindow::getCallBusinesses);
        callWindowWrapper.leftJoin(CallBusiness.class, "cb", p -> p.eq(CallBusiness::getDelFlag, 0).eq(CallBusiness::getState, "5").eq(CallBusiness::getWinCode, CallWindow::getWinCode).ge(CallBusiness::getReqTime, beginTime));
        callWindowWrapper.eq(CallWindow::getIsEnable, 1);
        callWindowWrapper.eq(CallWindow::getDelFlag, 0);
        List<CallWindow> callWindowsList = callWindowMapper.selectJoinList(CallWindow.class, callWindowWrapper);
        if (CollectionUtils.isEmpty(callWindowsList) && CollectionUtils.isNotEmpty(noBussinessList)){
            throw new RuntimeException("没有启用的窗口！");
        }

        for (CallWindow callWindow : callWindowsList) {
            int size = CollectionUtils.isEmpty(callWindow.getCallBusinesses()) ? 0 : callWindow.getCallBusinesses().size();
            callWindow.setBusinessesCount(size);
        }
        for (CallBusiness callBusiness : noBussinessList) {
            callWindowsList.sort((o1, o2) -> o1.getBusinessesCount() - o2.getBusinessesCount());
            CallWindow callWindow = callWindowsList.get(0);
            callBusiness.setWinCode(callWindow.getWinCode());
            callBusiness.setWinName(callWindow.getWinName());
            callWindow.setBusinessesCount(callWindow.getBusinessesCount() + 1);
            this.updateById(callBusiness);
        }
        MessageTemplate messageTemplate = new MessageTemplate();
        messageTemplate.setMessage(winCode);
        messageTemplate.setType("closeWindow");
        WebSocketUtils.sendAllMessage(messageTemplate);
        return Result.succ(1, "关闭成功", null);
    }

    private double getAvgTime(String windowCode) {
        // 获取今天00:00:00 的时间戳
        Timestamp beginTime = DateUtil.beginOfDay(DateUtil.date()).toTimestamp();
        LambdaQueryWrapper<CallBusiness> wrapper = new LambdaQueryWrapper<>();
        wrapper.ge(CallBusiness::getReqTime, beginTime);
        wrapper.eq(CallBusiness::getWinCode, windowCode);
        wrapper.eq(CallBusiness::getState, "10");
        wrapper.eq(CallBusiness::getDelFlag, 0);
        List<CallBusiness> callBusinesses = callBusinessMapper.selectList(wrapper);
        if (CollectionUtils.isNotEmpty(callBusinesses)) {
            // 获取callBusinesses集合中avgTime的平均数
            return callBusinesses.stream().filter(a -> Objects.nonNull(a.getAvgTime())).mapToInt(CallBusiness::getAvgTime).average().orElse(0);
        } else {
            return 0;
        }

    }
}
